iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 27
1
Modern Web

30天走訪Progressive Web Apps(PWAs)系列 第 27

Day27-Push Notification之成為訂閱用戶(Firebase實作)

  • 分享至 

  • xImage
  •  

今天要來模擬從伺服器端發送推播,
在這邊我們使用firebase來實作
首先,我們要回到firebase-tools的資料夾,安裝web-push套件

cd functions/

接著輸入指令

npm install --save web-push

https://ithelp.ithome.com.tw/upload/images/20180113/20103808k2D3l1Y5Wa.png

安裝後,修改一下package.json,讓我們可以使用該指令碼

  "scripts":{
    "web-push": "web-push"
  }

設定完之後,就可以透過執行該套件

npm run web-push

但除了昨天的方法,現在使用第二個方法
這方法需要公鑰和私鑰來驗證同一個伺服器發出的推播
透過底下指令碼可以產生需要的Public KeyPrivate Key

npm run web-push generate-vapid-keys

https://ithelp.ithome.com.tw/upload/images/20180113/20103808B69FggUbuB.png

現在有金鑰後,回到昨天setPushSubscribe()設定推播通知的地方。

navigator.serviceWorker.ready
        .then(function(sw){
            reg = sw;
          return sw.pushManager.getSubscription();
        })
        .then(function(sub){
            if(sub === null){
                //建立新的訂閱            
            }else{
                //已經訂閱
            }
        })

現在當裝置是新的用戶,我們就要設定pushManager.subscribe並將Public Key設定applicationServerKey

if(sub === null)
{
    //建立新的訂閱
    var vapidPKey = 'BERFARN6mum_Jl39dKxPx_veR9_bLHnXs5GHn63zLwbPAebmn-IeLMCuzeyFIZNnQR-dGZO_WdxC7xak6W9p6Mc';
    var convertedVapidPKey = urlBase64ToUint8Array(vapidPKey);
    return reg.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: convertedVapidPKey
    });
}

指令上的公鑰是base64 網址安全編碼,但推播預設的是UInt8Array格式,
因此在丟給PushManager之前,要將金鑰轉型。
轉型後再將值放入applicationServerKey

function urlBase64ToUint8Array(base64String){
    var padding = '='.repeat((4 - base64String.length % 4) % 4);
    var base64 = (base64String + padding)
        .replace(/\-/g, '+')
        .replace(/_/g,'/');
    var rawData = window.atob(base64);
    var outputArr = new Uint8Array(rawData.length);

    for (var i = 0; i < rawData.length; ++i ){
        outputArr[i] = rawData.charCodeAt(i);
    }    
    return outputArr;
}

此為轉型用的功能

subscribe()成功後,一樣回傳Promise型別,這時候我們可以將訂閱用戶的資料存進資料庫,在推播的時候,就能將訊息推給資料庫既有的用戶群。
因此,在後面要繼續接then()來做存入資料庫的動作

.then(function(newSub){
    return fetch('https://days-pwas-practice.firebaseio.com/subscriptions.json', {
        method: 'POST',
        headers: {
            'Content-TYpe': 'application/json',
            'Accept': 'application/json'
        },
        body: JSON.stringify(newSub)
    });
})

如果是新用戶,會進入此流程,透過fetch將訂閱戶的資料存入firebase中,
這邊我們命名新的json格式資料表,稱subscriptions.json
假如傳送成功,雲端上就會出現資料。

為了偵錯方便,fetch事件一樣是回傳Promise型別,在後面寫thencatch來驗證流程。

.then(function(response){
    if(response.ok)
        displayNotification();
})
.catch(function(err){
    console.log('訂閱失敗',err);
});

假如POST成功,且responseok就顯示「推播訊息」,
如果失敗,就顯示「訂閱失敗」和錯誤訊息。

測試

  1. 清除快取紀錄
  2. 點選訂閱按鈕
    https://ithelp.ithome.com.tw/upload/images/20180113/20103808E5fJ2cIeeI.png
    右下角成功出現了訊息視窗!

接著檢查Firebase的資料庫
https://ithelp.ithome.com.tw/upload/images/20180113/20103808vlJ9zLqnw0.png
成功的多了一筆subscriptions的資料,資料裡面存著3個內容
endpointURL,當我們將訊息含下面的金鑰一起傳到此URLPush Server會將內容確切傳送給指定的裝置。
endpoint url中含有唯一值的辨識字串,可以幫助對應正確的裝置,而且這個值是不公開的所以使用者無法透過URL去追蹤到使用者,
此外,PWA是運行在HTTPS的環境下,這也確保了Push Server和伺服器溝通的管道是安全的,但不保證Push Server本身安全,因此我們仍然要注意的是資料傳遞基本的加密,及不透過第三方檢查。

流程解釋

在用戶端:

  1. 訂閱推播
  2. 將訂閱資料傳給伺服器(如我們上面所測試)

伺服器

  1. 準備推播訊息
  2. 將訊息含public key加密
  3. 將加密後的資料送給endpoint的URL

訊息會傳遞給指定的用戶,並喚醒瀏覽器的service worker觸發push事件。

  1. 這時候在push事件監聽中,接收到推播訊息
  2. 可以客製要顯示的邏輯
  3. 顯示給客戶端裝置

總結

今天我們完成與Firebase串連Subscribe的基本設定,接下來,我們就可以針對有訂閱的使用者發出推播訊息,Push Notfication也就即將進入尾聲啦~

學習資源

[https://blog.mozilla.org/services/2016/04/04/using-vapid-with-webpush/](Vapid Key)
https://gist.github.com/borismus/1032746
[https://developers.google.com/web/fundamentals/codelabs/push-notifications/](Code labs)
[https://developers.google.com/web/ilt/pwa/introduction-to-push-notifications](介紹PUSH Notification)

GitHub

https://github.com/DakHarry/30day-pwas-practice


上一篇
Day26-Push API與推播互動監聽事件
下一篇
Day28-Push Notification伺服器推播訊息實作
系列文
30天走訪Progressive Web Apps(PWAs)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言